// 实现这个项目的构建任务

const {src, dest, parallel, series, watch} = require('gulp')

const del = require('del')

//避免手动加载插件
const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins()

//能由watch监视文件变化，将新页面同步到浏览器插件
const browserSync = require('browser-sync')
const bs = browserSync.create()

const eslint = require('gulp-eslint')
const rsync = require('gulp-rsync')

const log = require('fancy-log')

//嵌入进页面的数据
//swig作者鼓励使用gulp-data的方式从json里读
//那样还得和package.json里的数据merge，暂时没这么做
const data = {
  menus: [
    {
      name: 'Home',
      icon: 'aperture',
      link: 'index.html'
    },
    {
      name: 'About',
      link: 'about.html'
    },
    {
      name: 'Contact',
      link: '#',
      children: [
        {
          name: 'Twitter',
          link: 'https://twitter.com/woflow'
        },
        {
          name: 'divider'
        },
        {
          name: 'About',
          link: 'https://github.com/woflow'
        }
      ]
    }
  ],
  pkg: require('./package.json'),
  date: new Date()
}

//压缩和复制字体，主要是压缩svg
const fonts = () => {
  return src('src/assets/fonts/**', {base: 'src'})  //带上base能保留src后的路径
    .pipe(plugins.imagemin())
    .pipe(dest('dist'))
}

//压缩和复制图片
const images = () => {
  return src('src/assets/images/**', {base: 'src'})
    .pipe(plugins.imagemin())
    .pipe(dest('dist'))
}

//压缩和复制public其他文件
const publicFiles = () => {
  return src('public', {base: 'public'})
    .pipe(plugins.imagemin())
    .pipe(dest('dist'))
}

//babel编译js，复制到temp里，触发浏览器刷新
const script = () => {
  return src('src/assets/scripts/*.js', {base: 'src'})
  //需要安装@babel/core和@babel/preset-env，安装babel内核和指定使用的preset
    .pipe(plugins.babel({presets: ['@babel/preset-env']}))
    .pipe(dest('temp'))
    //触发浏览器刷新，stream true是必需的，pipe只接受流处理，不加会报错
    .pipe(bs.reload({stream: true}))
}

//sass编译scss，复制到temp里，触发浏览器刷新
const style = () => {
  return src('src/assets/styles/*.scss', {base: 'src'})
  //有了outputStyle expanded，css的后半大括号会换行，人看着舒服
    .pipe(plugins.sass({outputStyle: 'expanded'}))
    .pipe(dest('temp'))
    .pipe(bs.reload({stream: true}))
}

//swig编译html，支持html block，变量，for if等语句
const page = () => {
  return src('src/*.html', {base: 'src'})
  //关闭缓存，防止页面不会更新最新的改动
    .pipe(plugins.swig({data, defaults: {cache: false}}))
    .pipe(dest('temp'))
    .pipe(bs.reload({stream: true}))
}

//上线前采用useref合并一些文件，并且对js,css,html进行压缩
const useref = () => {
  return src('temp/*.html', {base: 'temp'})
  //对html引用的文件给出寻找的目录，temp是./的文件，.是node_modules的文件
  //常用的temp放在前面提高效率
    .pipe(plugins.useref({searchPath: ['temp', '.']}))
    .pipe(plugins.if(/.js$/, plugins.uglify()))
    .pipe(plugins.if(/.css$/, plugins.cleanCss()))
    .pipe(plugins.if(/.html$/, plugins.htmlmin({
      //删除换行符
      collapseWhitespace: true,
      //压缩html里内嵌的css和js
      minifyCSS: true,
      minifyJS: true
    })))
    .pipe(dest('dist'))
}

//监视文件变化，触发相应的操作，并最后触发浏览器刷新
const serve = () => {
  watch('src/assets/styles/*.scss', style)
  watch('src/assets/scripts/*.js', script)
  watch('src/*.html', page)
  watch([
    'src/assets/images/**',
    'src/assets/fonts/**',
    'public/**'
  ], bs.reload)

  bs.init({
    //不弹右上角的提示
    notify: false,
    port: 2090,
    // 是否自动打开浏览器
    // open: false,
    // 监视文件路径，现在代码使用的是针对几个路径的方式，所以注释这行
    // files: 'dist/**',
    server: {
      baseDir: ['temp', 'src', 'public'],
      routes: {
        '/node_modules': 'node_modules'
      }
    }
  })
}

const lint = () => {
  return src(['src/assets/scripts/*.js'])
    .pipe(eslint())
    .pipe(eslint.format())
    .pipe(eslint.failAfterError())
}

const compile = parallel(page, series(lint, script), style)

const start = series(compile, serve)

//分成dist和temp的主要原因是useref会同时读和写，如果读写同一个文件会导致写入失败
const clean = () => {
  return del(['dist', 'temp'])
}

const build = series(
  clean,
  parallel(
    series(compile, useref),
    images,
    fonts,
    publicFiles
  )
)

const sync = () => {
  return src('dist/**')
    // .pipe(rsync({
    //   root: 'dist/',
    //   hostname: 'example.com',
    //   destination: 'path/to/site/',
    //   progress: true,
    //   incremental: true,
    //   relative: true,
    //   emptyDirectories: true,
    //   recursive: true,
    //   clean: true,
    //   exclude: [],
    // }))
    .on('end', function(){log('Deploying')})
}

const deploy = series(
  build,
  sync
)

module.exports = {
  clean,
  lint,
  serve,
  build,
  start,
  deploy
}
